﻿using System;
using System.Configuration;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;

namespace Client
{
    public partial class MainForm : Form
    {
        private BinaryReader _br;
        private BinaryWriter _bw;
        private TcpClient _client;

        public MainForm()
        {
            InitializeComponent();
            string serverIp = ConfigurationManager.ConnectionStrings["serverIP"].ConnectionString;
            string serverPort = ConfigurationManager.ConnectionStrings["serverPort"].ConnectionString;
            txtAddress.Text = serverIp;
            txtPort.Text = serverPort;
            StartClient(serverIp, int.Parse(serverPort));
        }

        private void BtnSendMsgClick(object sender, EventArgs e)
        {
            ListBox.SelectedIndexCollection indexs = listChooseClient.SelectedIndices;
            string msg = txtSendMsg.Text;
            for (int i = 0; i < indexs.Count; i++)
            {
                int index = indexs[i];
                var userName = (string)listChooseClient.Items[index];
                SendToClient(userName, msg);
                AddTalkMessage(String.Format("向{0}说：{1}", userName, msg));
            }
        }

        private void SendToClient(string userName, string msg)
        {
            SendMessage(1);
            SendMessage(userName);
            SendMessage(msg);
        }

        private void MainFormFormClosing(object sender, FormClosingEventArgs e)
        {
            StopClient();
        }

        /// <summary>开启客户端</summary>
        private void StartClient(string serverIp, int serverPort)
        {
            try
            {
                _client = new TcpClient(serverIp, serverPort);

                //获取网络流
                NetworkStream networkStream = _client.GetStream();
                //将网络流作为二进制读写对象
                _br = new BinaryReader(networkStream);
                _bw = new BinaryWriter(networkStream);
                ChangeStatus(true);
                var threadReceive = new Thread(ReceiveData) { IsBackground = true };
                threadReceive.Start();
            }
            catch (Exception)
            {
                ChangeStatus(false);
                AddTalkMessage("服务器未开启！");
            }
        }

        /// <summary>提示是否与服务器连接</summary>
        private void ChangeStatus(bool status)
        {
            if (labelStatus.InvokeRequired)
            {
                StatusDelegate d = ChangeStatus;
                labelStatus.Invoke(d, new object[] { status });
            }
            else
            {
                labelStatus.Text = status ? "Success connected..." : "Failure connected...";
            }
        }

        /// <summary>处理接收的服务器端数据</summary>
        private void ReceiveData()
        {
            while (true)
            {
                short receiveNum;
                try
                {
                    //从网络流中读出字符串
                    //此方法会自动判断字符串长度前缀，并根据长度前缀读出字符串
                    //如果服务器异常退出，则会产生异常
                    receiveNum = _br.ReadInt16();
                }
                catch
                {
                    AddTalkMessage("与服务器失去联系！");
                    ChangeStatus(false);
                    StopClient();
                    break;
                }
                switch (receiveNum)
                {
                    //0代表服务器发来的消息
                    case 0:
                        AddTalkMessage("[服务器]说：" + _br.ReadString());
                        break;
                    //1代表用户发来的消息
                    case 1:
                        AddTalkMessage(string.Format("{0}说：{1}",
                                                     _br.ReadString(), _br.ReadString()));
                        break;
                    //2代表用户登录信息
                    case 2:
                        short onLineNum = _br.ReadInt16();
                        for (int i = 0; i < onLineNum; i++)
                        {
                            AddListUser(_br.ReadString());
                        }
                        break;
                    //3代表用户注销登录信息
                    case 3:
                        RemoveListUser(_br.ReadString());
                        break;
                    default:
                        AddTalkMessage("纳尼，这是什么意思：" + receiveNum);
                        break;
                }
            }
        }

        private void AddListUser(string userName)
        {
            if (listChooseClient.InvokeRequired)
            {
                MessageDelegate d = AddListUser;
                listChooseClient.Invoke(d, new object[] { userName });
            }
            else
            {
                listChooseClient.Items.Add(userName);
            }
        }

        private void RemoveListUser(string remoteEndPoint)
        {
            if (listChooseClient.InvokeRequired)
            {
                MessageDelegate d = RemoveListUser;
                listChooseClient.Invoke(d, new object[] { remoteEndPoint });
            }
            else
            {
                for (int i = 0; i < listChooseClient.Items.Count; i++)
                {
                    object item = listChooseClient.Items[i];
                    if ((string)item != remoteEndPoint) continue;
                    listChooseClient.Items.Remove(item);
                    break;
                }
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="num">短整数</param>
        private void SendMessage(short num)
        {
            try
            {
                //将短整数写入网络流，此方法会自动附加字符串长度前缀
                _bw.Write(num);
                _bw.Flush();
            }
            catch
            {
                AddTalkMessage("发送失败!");
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="msg">消息</param>
        public void SendMessage(string msg)
        {
            try
            {
                //将字符串写入网络流，此方法会自动附加字符串长度前缀
                _bw.Write(msg);
                _bw.Flush();
            }
            catch
            {
                AddTalkMessage("发送失败!");
            }
        }

        /// <summary> 在txtMsg中追加聊天信息</summary>
        private void AddTalkMessage(string message)
        {
            try
            {
                if (txtMsg.InvokeRequired)
                {
                    MessageDelegate d = AddTalkMessage;
                    txtMsg.Invoke(d, new object[] { message });
                }
                else
                {
                    txtMsg.AppendText(message + Environment.NewLine);
                    txtMsg.ScrollToCaret();
                }
            }
            catch
            {
                Application.Exit();
            }
        }

        /// <summary>关闭客户端</summary>
        private void StopClient()
        {
            //未与服务器连接前client为null
            if (_client == null) return;
            _br.Close();
            _bw.Close();
            _client.Close();
        }

        #region Nested type: MessageDelegate

        private delegate void MessageDelegate(string message);

        #endregion

        #region Nested type: StatusDelegate

        private delegate void StatusDelegate(bool status);

        #endregion
    }
}